package com.beordie.version_2.context;

import com.beordie.annotation.BODAutowried;
import com.beordie.annotation.BODController;
import com.beordie.annotation.BODResource;
import com.beordie.annotation.BODService;
import com.beordie.version_2.aop.BODDefaultAopProxyFactory;
import com.beordie.version_2.aop.config.BODAopConfig;
import com.beordie.version_2.aop.support.BODAdviseSupport;
import com.beordie.version_2.beans.BODBeanWrapper;
import com.beordie.version_2.beans.config.BODBeanDefinition;
import com.beordie.version_2.beans.support.BODBeanDefinitionReader;
import com.beordie.version_2.beans.support.BODDefaultListableBeanFactory;
import com.beordie.version_2.core.BODBeanFactory;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @Description
 * @Date 2022/2/14 8:36
 * @Created 30500
 */
public class BODApplicationContext implements BODBeanFactory {

    private BODDefaultListableBeanFactory register = new BODDefaultListableBeanFactory();
    private BODDefaultAopProxyFactory factory = new BODDefaultAopProxyFactory();

    private BODBeanDefinitionReader reader = null;

    /**
     * 循环依赖的表示
     */
    private Set<String> singletonCurrentlyInCreation = new HashSet<>();

    /**
     * 一级缓存
     */
    private Map<String, Object> singletonObjects = new HashMap<>();

    /**
     * 二级缓存
     */
    private Map<String, Object> earlySingletonObjects = new HashMap<>();

    private Map<String, BODBeanWrapper> factoryBeanInstanceCache = new HashMap<>();

    /**
     * 三级缓存
     */
    private Map<String, Object> factoryBeanObjectCache = new HashMap<>();

    public BODApplicationContext(String ... config) {
        //  1.加载配置文件
        this.reader = new BODBeanDefinitionReader(config);

        //  2.解析配置文件封装成 beandefinition 对象
        List<BODBeanDefinition> beanDefinitions = this.reader.loadBeanFefinitions();

        //  3.所有配置信息缓存起来
        this.register.doRegistBeanDefinition(beanDefinitions);

        //  4.加载非延时加载的 bean
        doLoadInstance();
    }

    /**
     * IOC 对象实例化
     */
    private void doLoadInstance() {
        for (Map.Entry<String, BODBeanDefinition> entry : this.register.bodBeanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            if (!entry.getValue().isLazyInit()) {
                getBean(beanName);
            }
        }
    }

    @Override
    public Object getBean(Class beabClass) {
        return getBean(beabClass.getName());
    }

    @Override
    public Object getBean(String beanName) {
        //  1.获取 beanDefinition 配置信息
        BODBeanDefinition definition = this.register.bodBeanDefinitionMap.get(beanName);

        Object singleton = getSingleton(beanName, definition);
        if (singleton != null) { return singleton; }
        if (!this.singletonCurrentlyInCreation.contains(beanName)) {
            this.singletonCurrentlyInCreation.add(beanName);
        }
        //  2.实例化对象
        Object instance = instantiateBean(beanName, definition);
        //  3.封装 wrapper 对象
        BODBeanWrapper wrapper = new BODBeanWrapper(instance);
        //  4.依赖注入
        populateBean(beanName, definition, wrapper);
        //  5.保存 IOC 容器
        this.factoryBeanInstanceCache.put(beanName, wrapper);

        return wrapper.getWrappedInstance();
    }

    /**
     * 先期获取对象
     * @param beanName
     * @param definition
     * @return
     */
    private Object getSingleton(String beanName, BODBeanDefinition definition) {
        //  1.一级缓存中拿
        Object bean = this.singletonObjects.get(beanName);
        //  2.一级缓存没有, 有创建标记则表示循环依赖
        if (bean == null && this.singletonCurrentlyInCreation.contains(beanName)) {
            bean = this.earlySingletonObjects.get(beanName);
            //  3.从三级缓存中拿, 也就是进行对象的创建
            if (bean == null) {
                bean = instantiateBean(beanName, definition);
                this.earlySingletonObjects.put(beanName, bean);
            }
        }

        return bean;
    }

    /**
     * DI 注入
     * @param beanName
     * @param definition
     * @param wrapper
     */
    private void populateBean(String beanName, BODBeanDefinition definition, BODBeanWrapper wrapper) {
        Object instance = wrapper.getWrappedInstance();
        Class<?> clazz = wrapper.getWrappedClass();

        if (!(clazz.isAnnotationPresent(BODController.class) || clazz.isAnnotationPresent(BODService.class))) {
            return;
        }
        for (Field field : clazz.getDeclaredFields()) {
            String name = null;
            if (field.isAnnotationPresent(BODAutowried.class)) { // 按照类型注入
                name = field.getName();
            } else if (field.isAnnotationPresent(BODResource.class)) { // 按照名称进行注入
                name = field.getAnnotation(BODResource.class).name().trim();
                if ("".equals(name)) name = field.getName();
            } else {
                continue;
            }
            //  字段进行赋值
            field.setAccessible(true);
            try {
                field.set(instance, getBean(name));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 实际创建对象
     * @param beanName
     * @param definition
     * @return
     */
    private Object instantiateBean(String beanName, BODBeanDefinition definition) {
        if(definition.isSingleton() && this.factoryBeanObjectCache.containsKey(beanName)){
            return this.factoryBeanObjectCache.get(beanName);
        }
        String className = definition.getBeanClassName();
        Object instance = null;
        try {
            Class<?> clazz = Class.forName(className);
            instance = clazz.newInstance();

            //  如果是代理对象, 触发 AOP 处理逻辑
            BODAdviseSupport config = instantionAopConfig(definition);
            config.setTargetClass(clazz);
            config.setTargetInstance(instance);

            //  符合代理规则
            if (config.pointCutMatch()) {
                instance = factory.createAopProxy(config).getProxy();
            }
            this.factoryBeanObjectCache.put(beanName, instance);
            this.factoryBeanObjectCache.put(clazz.getName(), instance);
            for (Class<?> i : clazz.getInterfaces()) {
                this.factoryBeanObjectCache.put(i.getName(), instance);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }

    /**
     * 获取切面的配置信息
     * @param definition
     * @return
     */
    private BODAdviseSupport instantionAopConfig(BODBeanDefinition definition) {
        BODAopConfig config = new BODAopConfig();
        config.setPointCut(this.reader.getConfig("pointCut"));
        config.setAspectClass(this.reader.getConfig("aspectClass"));
        config.setAspectBefore(this.reader.getConfig("aspectBefore"));
        config.setAspectAfter(this.reader.getConfig("aspectAfter"));
        config.setAspectAfterThrow(this.reader.getConfig("aspectAfterThrow"));
        config.setAspectAfterThrowingName(this.reader.getConfig("aspectAfterThrowingName"));
        return new BODAdviseSupport(config);
    }

    /**
     * BeanDefinition 的数量
     * @return
     */
    public int getBeanDefinitionCount() {
        return this.register.bodBeanDefinitionMap.size();
    }

    /**
     * BeanDefinition 名称列表
     * @return
     */
    public String[] getBeanDefinitionNames() {
        return this.register.bodBeanDefinitionMap.keySet().toArray(new String[0]);
    }

    /**
     * 获取配置值
     * @param parameter
     * @return
     */
    public String getConfig(String parameter) {
        return reader.getConfig(parameter);
    }
}
